<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <meta name="xbsj-labels" content="Cesium示例">
    </meta>
    <title>Cesium自定义材质</title>
    <!-- 0 引入js文件 -->
    <script src="../../XbsjEarth/XbsjEarth.js"></script>
    <script src="./scripts/vue.min.js"></script>
    <style>
        html,
        body {
            width: 100%;
            height: 100%;
            margin: 0px;
            padding: 0px;
        }

        .box span {
            display: block;
            margin-top: 10px;
        }

        .defultbtn {
            display: inline-block;
            text-align: center;
            min-width: 60px;
            height: 38px;
            padding: 0 10px;
            line-height: 38px;
            border-radius: 100px;
            border: 1px solid #C9C9C9;
            background-color: #FFF;
            color: #555;
            cursor: pointer;
        }

        .defultbtn:hover {
            background-color: #b3daf8;
        }

        .btnon {
            background-color: #1E9FFF;
            color: #fff;
            border: 1px solid #1E9FFF;
        }
    </style>
</head>

<body>

    <div id="vueApp" style="width: 100%; height: 100%; background: grey; position: relative;">
        <earth-comp></earth-comp>
    </div>

    <script>
        var myBox = {}, colorMaterial = {}, imageMaterial = {}, compositeMaterial = {}, customMaterial = {};
        // 1 创建Earth的vue组件
        var EarthComp = {
            template: `
          <div style="width: 100%; height: 100%">
              <div ref="earthContainer" style="width: 100%; height: 100%">
              </div>
              <div class="box" style="position: absolute; left: 18px; top: 18px; color: white; background: rgba(0, 0, 0, 0.6); padding: 20px; border-radius: 25px;min-width:200px; font-size:24px; font-family: 宋体;">
                  <div class="defultbtn" :class="{'btnon':colorMaterialShow}" @click="colorMaterialClick">纯色材质</div>
                  <div class="defultbtn" :class="{'btnon':imageMaterialShow}" @click="imageMaterialClick">图像材质</div>
                  <div class="defultbtn" :class="{'btnon':compositeMaterialShow}" @click="compositeMaterialClick">组合材质</div>
                  <div class="defultbtn" :class="{'btnon':customMaterialShow}" @click="customMaterialClick">自定义Shader材质</div><br/>
              </div>
          </div>
      `,
            data() {
                return {
                    _earth: undefined, // 注意：Earth和Cesium的相关变量放在vue中，必须使用下划线作为前缀！
                    _tileset: undefined,
                    colorMaterialShow: false,
                    imageMaterialShow: false,
                    compositeMaterialShow: false,
                    customMaterialShow: false
                };
            },
            // 1.1 资源加载
            mounted() {
                // 1.2.1 创建地球
                var earth = new XE.Earth(this.$refs.earthContainer);

                // 1.2.2 添加默认地球影像
                earth.sceneTree.root = {
                    "children": [
                        {
                            "czmObject": {
                                "name": "默认离线影像",
                                "xbsjType": "Imagery",
                                "xbsjImageryProvider": {
                                    "createTileMapServiceImageryProvider": {
                                        "url": XE.HTML.cesiumDir + 'Assets/Textures/NaturalEarthII',
                                        "fileExtension": 'jpg',
                                    },
                                    "type": "createTileMapServiceImageryProvider"
                                }
                            }
                        },
                    ]
                };
                const viewer = earth.czm.viewer;
                var boxLength = 100000.0;
                var position = Cesium.Cartesian3.fromDegrees(116.39, 39.9, 0.5 * boxLength);
                var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position);
                // 0 立方体顶点位置标号，以及坐标系示意图
                // 立方体
                //    v6----- v5
                //   /|      /|
                //  v1------v0|
                //  | |     | |
                //  | |v7---|-|v4
                //  |/      |/
                //  v2------v3
                // 坐标系
                //  z
                //  | /y
                //  |/
                //  o------x
                // 1 定义位置数组
                var v0 = [0.5, -0.5, 0.5];
                var v1 = [-0.5, -0.5, 0.5];
                var v2 = [-0.5, -0.5, -0.5];
                var v3 = [0.5, -0.5, -0.5];
                var v4 = [0.5, 0.5, -0.5];
                var v5 = [0.5, 0.5, 0.5];
                var v6 = [-0.5, 0.5, 0.5];
                var v7 = [-0.5, 0.5, -0.5];
                var rawVertex = [
                    // 下 -z
                    ...v2, ...v3, ...v4, ...v7,
                    // 前 -y
                    ...v2, ...v3, ...v0, ...v1,
                    // 后 +y
                    ...v4, ...v7, ...v6, ...v5,
                    // 左 -x
                    ...v7, ...v2, ...v1, ...v6,
                    // 右 +x
                    ...v3, ...v4, ...v5, ...v0,
                    // 上 +z
                    ...v1, ...v0, ...v5, ...v6,
                ];
                // 乘上box的长度
                var boxVertex = rawVertex.map(function (v) {
                    return v * boxLength;
                });
                var positions = new Float64Array(boxVertex);
                // 2 定义法向数组
                var npx = [1, 0, 0];
                var nnx = [-1, 0, 0];
                var npy = [0, 1, 0];
                var nny = [0, -1, 0];
                var npz = [0, 0, 1];
                var nnz = [0, 0, -1];
                var normals = new Float32Array([
                    // 下 -z
                    ...nnz, ...nnz, ...nnz, ...nnz,
                    // 前 -y
                    ...nny, ...nny, ...nny, ...nny,
                    // 后 +y
                    ...npy, ...npy, ...npy, ...npy,
                    // 左 -x
                    ...nnx, ...nnx, ...nnx, ...nnx,
                    // 右 +x
                    ...npx, ...npx, ...npx, ...npx,
                    // 上 +z
                    ...npz, ...npz, ...npz, ...npz,
                ]);
                // 3 定义纹理数组
                var sts = new Float32Array([
                    0, 0, 1, 0, 1, 1, 0, 1,
                    0, 0, 1, 0, 1, 1, 0, 1,
                    0, 0, 1, 0, 1, 1, 0, 1,
                    0, 0, 1, 0, 1, 1, 0, 1,
                    0, 0, 1, 0, 1, 1, 0, 1,
                    0, 0, 1, 0, 1, 1, 0, 1,
                ]);
                // 4 定义索引
                var indices = new Uint16Array([
                    0, 1, 2, 0, 2, 3,
                    4, 5, 6, 4, 6, 7,
                    8, 9, 10, 8, 10, 11,
                    12, 13, 14, 12, 14, 15,
                    16, 17, 18, 16, 18, 19,
                    20, 21, 22, 20, 22, 23,
                ]);
                // 5 创建Primitive
                myBox = viewer.scene.primitives.add(new Cesium.Primitive({
                    geometryInstances: new Cesium.GeometryInstance({
                        geometry: new Cesium.Geometry({
                            attributes: {
                                position: new Cesium.GeometryAttribute({
                                    componentDatatype: Cesium.ComponentDatatype.DOUBLE,
                                    componentsPerAttribute: 3,
                                    values: positions
                                }),
                                normal: new Cesium.GeometryAttribute({
                                    componentDatatype: Cesium.ComponentDatatype.FLOAT,
                                    componentsPerAttribute: 3,
                                    values: normals
                                }),
                                st: new Cesium.GeometryAttribute({
                                    componentDatatype: Cesium.ComponentDatatype.FLOAT,
                                    componentsPerAttribute: 2,
                                    values: sts
                                }),
                            },
                            indices: indices,
                            primitiveType: Cesium.PrimitiveType.TRIANGLES,
                            boundingSphere: Cesium.BoundingSphere.fromVertices(positions)
                        }),
                        // attributes : {
                        //     color : Cesium.ColorGeometryInstanceAttribute.fromColor(new Cesium.Color(1.0, 1.0, 0.0, 1.0))
                        // }
                    }),
                    // appearance: new Cesium.PerInstanceColorAppearance({
                    //     flat : true,
                    //     translucent : false
                    // }),
                    appearance: new Cesium.MaterialAppearance({
                        material: Cesium.Material.fromType('Image', {
                            image: './images/earth.png'
                        }),
                        //faceForward : true // 当绘制的三角面片法向不能朝向视点时，自动翻转法向，从而避免法向计算后发黑等问题
                        closed: true // 是否为封闭体，实际上执行的是是否进行背面裁剪
                    }),
                    modelMatrix: modelMatrix,
                    asynchronous: false
                }));

                viewer.camera.flyToBoundingSphere(new Cesium.BoundingSphere(position, 100000));

                // 6 创建material
                // 6.1 创建纯色material
                colorMaterial = new Cesium.Material({
                    fabric: {
                        type: 'Color',
                        uniforms: {
                            color: new Cesium.Color(1.0, 1.0, 0.0, 1.0)
                        },
                        components: {
                            diffuse: 'color.bgr',
                            alpha: 'color.a'
                        }
                    },
                    translucent: false
                });
                // 6.2 创建图像material
                imageMaterial = new Cesium.Material({
                    fabric: {
                        type: 'Image',
                        uniforms: {
                            image: './images/earth.png',
                            repeat: new Cesium.Cartesian2(1.0, 1.0),
                            color: new Cesium.Color(1.0, 1.0, 1.0, 1.0)
                        },
                        components: {
                            diffuse: 'texture2D(image, fract(repeat * materialInput.st)).rgb * color.rgb',
                            alpha: 'texture2D(image, fract(repeat * materialInput.st)).a * color.a'
                        }
                    },
                    translucent: false
                });
                // 6.3 创建组合material
                // Material创建几个material来组合使用，以下其写法
                compositeMaterial = new Cesium.Material({
                    fabric: {
                        type: 'OurMappedPlastic',
                        materials: {
                            diffuseMaterial: {
                                type: 'DiffuseMap',
                                uniforms: {
                                    image: './images/earth.png'
                                }
                            },
                            alphaMap: {
                                type: 'AlphaMap',
                                uniforms: {
                                    image: './images/FlameGrate.png',
                                    channel: 'r'
                                }
                            }
                        },
                        components: {
                            diffuse: 'diffuseMaterial.diffuse',
                            // specular: 'specularMaterial.specular',
                            // alpha: 'diffuseMaterial.diffuse.g',
                            alpha: 'alphaMap.alpha * 3.0',
                        },
                    },
                    translucent: function (material) {
                        // return material.uniforms.color.alpha < 1.0;
                        return false;
                    }
                });
                // 6.4 创建自定义shader的material
                // 模拟纯色到图像的过渡过程
                customMaterial = new Cesium.Material({
                    fabric: {
                        type: 'MyCustomShader1',
                        uniforms: {
                            image: './images/earth.png',
                            color: new Cesium.Color(1.0, 1.0, 0.0, 1.0),
                            cellAlpha: 0.3
                        },
                        source: `
                                uniform vec4 color;
                                uniform float cellAlpha;
                                czm_material czm_getMaterial(czm_materialInput materialInput)
                                {
                                    czm_material material = czm_getDefaultMaterial(materialInput);
                                    vec2 st = materialInput.st;
                                    float aa = st.s * st.t;
                                    vec3 halfColor = color.rgb * aa + texture2D(image, materialInput.st).rgb * (1.0 - aa);
                                    halfColor *= 0.5;
                                    material.diffuse = halfColor;
                                    material.emission = halfColor;
                                    // material.alpha = color.a * aa;
                                    material.alpha = 1.0;
                                    return material;
                                }
                            `
                    },
                    translucent: false
                });

                // 使用纯色材质
                // myBox.appearance.material = colorMaterial;
                // 使用图像材质
                // myBox.appearance.material = imageMaterial;
                // 使用组合材质
                // myBox.appearance.material = compositeMaterial;
                // 自定义Shader材质
                // myBox.appearance.material = customMaterial;

                // only for Debug
                window.earth = earth;
            },
            methods: {
                colorMaterialClick() {
                    myBox.appearance.material = colorMaterial;
                    this.colorMaterialShow = true;
                    this.imageMaterialShow = false;
                    this.compositeMaterialShow = false;
                    this.customMaterialShow = false;
                },
                imageMaterialClick() {
                    myBox.appearance.material = imageMaterial;
                    this.colorMaterialShow = false;
                    this.imageMaterialShow = true;
                    this.compositeMaterialShow = false;
                    this.customMaterialShow = false;
                },
                compositeMaterialClick() {
                    myBox.appearance.material = compositeMaterial;
                    this.colorMaterialShow = false;
                    this.imageMaterialShow = false;
                    this.compositeMaterialShow = true;
                    this.customMaterialShow = false;
                },
                customMaterialClick() {
                    myBox.appearance.material = customMaterial;
                    this.colorMaterialShow = false;
                    this.imageMaterialShow = false;
                    this.compositeMaterialShow = false;
                    this.customMaterialShow = true;
                }
            },
            // 1.2 资源销毁
            beforeDestroy() {
                this._earth = this._earth && this._earth.destroy();
            },
        }

        // 2 创建vue程序
        // XE.ready()用来加载Cesium.js等相关资源
        XE.ready().then(() => {
            var app = new Vue({
                el: '#vueApp',
                components: {
                    EarthComp,
                },
            });
        });
    </script>


</body>

</html>